# coding=utf-8
import numpy as np
import cv2
import matplotlib.pyplot as plt


def get4points(img: np.ndarray, thed, n):
    # 灰度和二值化
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, binary = cv2.threshold(gray, thed, 255, cv2.THRESH_BINARY)

    # 搜索轮廓
    contours, hierarchy = cv2.findContours(
        binary,
        cv2.RETR_LIST,
        cv2.CHAIN_APPROX_SIMPLE)

    # 按轮廓长度选取需要轮廓
    len_list = []
    for i in range(len(contours)):
        len_list.append(len(contours[i]))

    # 选第二长的
    sy = np.argsort(np.array(len_list))[-n]

    # 寻找顶点
    sum_list = []
    dif_list = []
    for i in contours[sy]:
        sum = i[0][0]+i[0][1]
        sum_list.append(sum)
        dif_list.append(i[0][0]-i[0][1])

    id_lb = np.argsort(np.array(sum_list))
    id_lb2 = np.argsort(np.array(dif_list))
    lu_id , rd_id = id_lb[0], id_lb[-1]
    ld_id , ru_id = id_lb2[0], id_lb2[-1]

    points = np.array([contours[sy][lu_id][0], contours[sy][rd_id][0],
                       contours[sy][ld_id][0], contours[sy][ru_id][0]])

    return points, contours, sy


def order_points(pts):
    # 初始化坐标点
    rect = np.zeros((4, 2), dtype = "float32")

    # 获取左上角和右下角坐标点
    s = pts.sum(axis = 1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]

    # 分别计算左上角和右下角的离散差值
    diff = np.diff(pts, axis = 1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]

    return rect


def four_point_transform(image, pts):
    # 获取坐标点，并将它们分离开来
    rect = order_points(pts)
    (tl, tr, br, bl) = rect
    # 计算新图片的宽度值，选取水平差值的最大值
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA), int(widthB))

    # 计算新图片的高度值，选取垂直差值的最大值
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA), int(heightB))

    # 构建新图片的4个坐标点
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype="float32")

    # 获取仿射变换矩阵并应用它
    M = cv2.getPerspectiveTransform(rect, dst)
    # 进行仿射变换
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

    # 返回变换后的结果
    return warped


def show_cmp_img(original_img, transform_img):
    _, axes = plt.subplots(1, 2)
    # 显示图像
    axes[0].imshow(original_img)
    axes[1].imshow(transform_img)
    # 设置子标题
    axes[0].set_title("original image")
    axes[1].set_title("transform image")
    plt.show()


# 读取图片
image = cv2.imread('6.jpg')

points, _, _ = get4points(image, 215, 2747)

# 获取原始的坐标点
pts = np.array(points, dtype="float32")

# 对原始图片进行变换
warped = four_point_transform(image, pts)
cv2.imwrite('ro3-output.jpg', warped)
#show_cmp_img(image, warped)